ルビを取る処理の習得記録 Part 3「正規表現が動いた!!」
正規表現惑星の探索
self[regexp] = val
正規表現 regexp にマッチした部分文字列全体を val で置き換えます。
おっと出た正規表現!
regexpは聞いたことない
注釈助かる……cFQ2f7LRuLYP.icon
指定したファイルから特定のパターン、あるいは文字列を含んだ行を検索し、該当する行表示するUNIXコマンド code:ruby
buf = "string"
p buf # => "s!!g"
これやりたいことに近いな
いいねnishio.icon
このbufってなんなんだろう?
yes!nishio.icon
https://gyazo.com/e4f4a60085630d827734fead243c8a40
code:Ruby
# coding: utf-8
Encoding.default_internal = __ENCODING__
buf = "ゴジラ"
p buf # -> "クジラ"
おー動いた!
https://gyazo.com/413fa91b7f7bd54c25dd48e3b5c33449https://gyazo.com/aecd64e3ac0624f24463dec802fcc6dc
プロンプト上でも動作確認
では次。ゴジラとある文をガメラにしたい場合にはどうしたらよいだろう?
1.
$ buf/ゴジ/ = "ガメ"
これは文字を指定しなきゃいけないので、今回の目的には合わない。
「ゴから始まってその次1文字目までを置換してください」とRubyさんに伝える方法がいる
たのしいRubyを見ると.が任意の一文字とマッチングする、とある(p.348)
あっここMijinko_SD.iconさんの言及で出たやつだ!
2.
こうか…?
$ buf/ゴ./ = "ガメ"
https://gyazo.com/e7e22babf3179fd4bb112cbeb5ccdf92
いけたー。このルートだな
さらにもう段階
"歌《うた》"とあるときに"《うた》"を""にするにはどうしたらよいか?(本質問題の一)
p.349に\zが文字列の末尾にマッチすると説明有り
実験だ!
https://gyazo.com/e080e141397807e8b0c1995e5840f802
ゴジラ→ゴジラSPの生成に成功
文字列の末尾の「ラ」を探して「ラSP」に置換してね
ということは…
https://gyazo.com/71d76e9bfc70c068dc66b0810068141a
まあそうですよね
戦闘が「ゴ」末尾が「ラ」の語句を「Godzilla: King of Monsters」に変える(変えたい)
もう少し読んだら回答があるはずだ
この正規表現で使われてる*や+の振る舞いって、データベースでの検索条件となんか似てるな データベース何にも知らんけど.icon
*を使う方法と+を使う手があるらしい
同じ文字や単語の繰り返しにマッチさせたいことがあります。たとえば、"Subject"という文字列のあとに、いくつか空白があって、その後ろに文字列が並んでいる行にマッチさせる」というような場合です(これは、電子メールの件名(サブジェクト)にマッチさせるためのパターンです)。
文字全てを指定したい時に.+か.*を使えばいいというのは覚えて損はないです
ここの記述重要だな?
いろいろ苦労したが/.*/が効いた
https://gyazo.com/76737dc51b4a56455b80e7934d4e80b2
これで歌《うた》を歌にできた!(終了条件2)
/emoji/tada.iconinajob.iconnishio.icontakker.icon
さらに次の問題。"歌《うた》の話《はなし》について"を"歌の話について"にするにはどうしたらよいか?
https://gyazo.com/ed031caf68302252016dd11dd8a341f1
code:ruby
buf = "歌《うた》の話《はなし》について"
こうなりますよね
これはわかる
Scrapbox上での[]の振る舞いや$ \TeXでの[]とおんなじことが起こってる
"歌《うた》の話《はなし》について"←この太字の部分が""になっているってわけだ
なので「行を読んでいく間に数回出てくるパターン」への対応策を考えなきゃならん
たのしいRubyを読み進めていたらこのあたりでsubメソッドとgsubメソッドが出てきた
subメソッドもgsubメソッドも、引数を2つ取ります。最初の引数には、マッチさせたいパターンを正規表現として指定します。2番目の引数には、マッチした部分と置き換える文字列を書きます。subメソッドは最初にマッチした部分だけを置き換えますが、gsubメソッドはマッチする部分すべてを置き換えます。(p.358)
code:ruby
buf = "歌《うた》の話《はなし》について"
p buf.sub(/《.*》/, "")
p buf.gsub(/《.*》/, "")
さてどうなる?
https://gyazo.com/2006c25f3316ba565ec71b7a4ac15a39
同じだ
説明のとおりでこうなるのは自然
マッチする条件は《.*》だし置き換えるのも""だから
なので改善すべき点は正規表現の書き方にありそう
+1inajob.iconnishio.icon
subgsubメソッドを使うと最初よりも行が短縮できる
これを使うとよいなあcFQ2f7LRuLYP.icon
^, $というのがあるらしい
これは行頭と行末
今回は行の内部にあるから使う必要は無さそう
読むのにじかんがかかる
キャプチャというのがあるのか
丸括弧 ( ) によってキャプチャをすることができます。括弧に囲まれた部分正規表現にマッチした前からn番目の開き括弧によって囲まれた部分式にマッチした文字列を後で参照することができます。
正規表現内では \1, \2, ... という記法で後方参照できます。また、\k<1>, \k<2>, ... や \k'1', \k'2', ... という記法を使うこともできます(10を越える数字を渡すことができます)。また、Regexp#match で得られた MatchData からは MatchData#[]で取り出せます。 0回以上の繰り返しを表す「*」と1回以上の繰り返しを表す「+」は、可能な限り長い部分にマッチします。逆に、マッチする可能性のある部分のうち一番短い部分にマッチさせる場合は、次のメタ文字を使います。
*? 0回以上の繰り返しのうち最短の部分
+? 1回以上の繰り返しのうち最短の部分
いいねwogikaze.iconinajob.iconnishio.icontakker.icon
https://gyazo.com/17bd990c5650f9aa72f39406e13186bdhttps://gyazo.com/ed5dcec92c100e18f5dd089817e284d6
行けた!
*と+の使い分けはまだわからん
✅2つの条件がある場合にどうなるか?
[#6字下げ]歌《うた》の話《はなし》について[#「歌の話について」は中見出し]
1. 《》
2. []
この両者をgsubで変換できればまずよし
二回処理を走らせるという手があるな
+1inajob.iconwogikaze.icon
僕が自分でやるとしてもそうしますnishio.icon
えっそうなんですかcFQ2f7LRuLYP.icon
てっきりプログラマは常に複数条件を華麗に分岐させてスパーッ!!とやるのかと思った(主語が大きい) 正規表現を使わない解法を考える場合2回処理をしない選択肢をとるかもinajob.icon
正規表現は、プログラミング言語内言語みたいなもので、細かい制御が難しい
Wiki文法の解析などをするときは正規表現を使わないケースがある
「正規表現を使わない場合」+1nishio.icon
正規表現を使う場合は、と書き忘れた。
正規表現を使って2つのルールを組み合わせて1回でやるコードは2倍よりも長くなる
今回の課題の範囲では2つってことになってるけど、すぐ「3つ目を追加したい」とかなる可能性がある
というあたりに思いを馳せてから「長期的視点でコスト最小なのは2回処理する方法だな」と判断する
コードを読んで理解が難しいより自分が制御できる範囲のものをまず使うwogikaze.icon
https://gyazo.com/ac5aca0219e707ce87c158300499e729
できたわ(できるんかい)
https://gyazo.com/71b10a6255d6d2f0dba02448ff1d5359
とりあえずこれでよし
本来は「複数の条件を指定して正規表現を行う」処理を行いたい
じゃあせっかくだしこれやってみよう
改行なしの一行データを上のスクリプトに放り込んだらどうなる?
code:Ruby
# coding: utf-8
Encoding.default_internal = __ENCODING__
buf = "この度《たび》、高濱虚子《たかはまきよし》さん・柳田國男先生《やなぎだくにをせんせい》[#ルビの「やなぎだくにをせんせい」はママ]と御一《ごいつ》しょに、この一部《いちぶ》の書物《しよもつ》を作《つく》ることになりました。その高濱《たかはま》さんの御領分《ごりようぶん》の俳句《はいく》と同樣《どうよう》に、短歌《たんか》といふものは、ほんとうに、日本國民《につぽんこくみん》自身《じしん》が生《う》み出《だ》したもので、とりわけ、きはめて古《ふる》い時代《じだい》に、出來上《できあが》つてゐたものであります。さうして、それが偶然《ぐうぜん》、私《わたし》の先生《せんせい》でもあり、またあなた方《がた》のこの文庫《ぶんこ》におけるおなじみでもある、柳田國男先生《やなぎだくにをせんせい》[#ルビの「やなぎだくにをせんせい」はママ]がお書《か》きの諺《ことわざ》の成《な》り立《た》ちとも、原因《げんいん》が竝行《へいかう》してゐるのは、不思議《ふしぎ》な御縁《ごえん》だとおもひます。"
buf2 = buf.gsub(/《.*?》/, "")
print buf2.gsub(/[.*?]/, "")
code:処理結果
この度、高濱虚子さん・柳田國男先生と御一しょに、この一部の書物を作ることになりました。その高濱さんの御領分の俳句と同樣に、短歌といふものは、ほんとうに、日本國民自身が生み出したもので、とりわけ、きはめて古い時代に、出來上つてゐたものであります。さうして、それが偶然、私の先生でもあり、またあなた方のこの文庫におけるおなじみでもある、柳田國男先生がお書きの諺の成り立ちとも、原因が竝行してゐるのは、不思議な御縁だとおもひます。
イェイイェーイ!cFQ2f7LRuLYP.icon
うーん達成感。
✅改行が含まれてる場合にどうするか?
今は変数bufに文字列を代入して、それをもとに処理している
https://gyazo.com/a413b7a8fbecb462f517da8de4fc9722
\n詩の話について\n
この\nを削除する
これは、必要な処理なのかな? 元の文書の改行は整形後も改行のままでよい気がするinajob.icon
おっとこれは文字ではなく改行を表してるんですかcFQ2f7LRuLYP.icon
消すと改行情報が亡くなってしまう?
改行情報が亡くなってしまう?←なんかfuneralになってしまった。面白いので残しておこう
pじゃなくてprintにすれば改行は見た目も改行になるはずinajob.icon
なりました!cFQ2f7LRuLYP.icon
たのしいRuby(p.32, 33)
たとえば、数値の100 と文字列の"100" を、print メソッドやputs メソッドで表示させると、どちらも単に「100」と表示されてしまいます。これでは本当はどちらのオブジェクトなのか、表示結果から確認できません。そんなときには、pメソッドを使うのが便利です。pメソッドなら、文字列と数値を違った形で表示してくれるのです。
(...)このように、文字列を出力する場合、「" "」で囲んで、表示してくれるわけです。これなら一目瞭然ですね。さらに、文字列の中に含まれる改行やタブなどの特殊な文字も、「\n」 や「\t」のように表示されます。
ナルホドネーcFQ2f7LRuLYP.icon
もう一度gsub(/\n.*?/)の処理をかけるという手もあるけど、もっとよい解決策があるに違いない
もっとエレガント(?)にしたい
短く、すっとするような
行情報があるときにどうなるか?
code:txt
この度《たび》、高濱虚子《たかはまきよし》さん・柳田國男先生《やなぎだくにをせんせい》[#ルビの「やなぎだくにをせんせい」はママ]と御一《ごいつ》しょに、この一部《いちぶ》の書物《しよもつ》を作《つく》ることになりました。
その高濱《たかはま》さんの御領分《ごりようぶん》の俳句《はいく》と同樣《どうよう》に、短歌《たんか》といふものは、ほんとうに、日本國民《につぽんこくみん》自身《じしん》が生《う》み出《だ》したもので、とりわけ、きはめて古《ふる》い時代《じだい》に、出來上《できあが》つてゐたものであります。
さうして、それが偶然《ぐうぜん》、私《わたし》の先生《せんせい》でもあり、またあなた方《がた》のこの文庫《ぶんこ》におけるおなじみでもある、柳田國男先生《やなぎだくにをせんせい》[#ルビの「やなぎだくにをせんせい」はママ]がお書《か》きの諺《ことわざ》の成《な》り立《た》ちとも、原因《げんいん》が竝行《へいかう》してゐるのは、不思議《ふしぎ》な御縁《ごえん》だとおもひます。
code:処理結果
この度、高濱虚子さん・柳田國男先生と御一しょに、この一部の書物を作ることになりました。
その高濱さんの御領分の俳句と同樣に、短歌といふものは、ほんとうに、日本國民自身が生み出したもので、とりわけ、きはめて古い時代に、出來上つてゐたものであります。
さうして、それが偶然、私の先生でもあり、またあなた方のこの文庫におけるおなじみでもある、柳田國男先生がお書きの諺の成り立ちとも、原因が竝行してゐるのは、不思議な御縁だとおもひます。
いよーし!Goodッ!